/**
 * 
 */
package uy.org.softtech.cssuite.helpers;

import static org.springframework.util.CollectionUtils.containsAny;
import static org.springframework.util.CollectionUtils.containsInstance;
import static org.springframework.util.CollectionUtils.isEmpty;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.xml.bind.annotation.XmlTransient;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

import uy.org.softtech.cssuite.entidad.usuario.Usuario;
import uy.org.softtech.cssuite.entidad.usuario.Permiso.Token;
import uy.org.softtech.cssuite.web.entidad.Autorizacion;
import uy.org.softtech.cssuite.web.entidad.DetalleUsuario;

/**
 * Clase con métodos utilitarios para trabajar con la seguridad en la aplicación.
 *
 * @author fabian.lobo
 */
@XmlTransient
public class HelperSeguridad {

	/** 
	 * Retorna el usuario que está actualmente logueado para el contexto actual, o null si no hay usuario logueado.
	 *
	 * @author fabian.lobo
	 */
	public synchronized static Usuario usuarioActual() {
		Usuario usuarioActual = null;
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication != null && authentication.getPrincipal() != null) {
			Object principal = authentication.getPrincipal();
			if (principal != null && principal instanceof DetalleUsuario) {
				usuarioActual = ((DetalleUsuario) principal).getUsuario();
			}
		}
		return usuarioActual;
	}

	/**
	 * Retorna los permisos para el usuario actualmente logueado.
	 * 
	 * @author fabian.lobo
	 * @see {@link Autorizacion}
	 */
	private synchronized static Set<GrantedAuthority> permisosDelUsuario() {
		Set<GrantedAuthority> authorities = new LinkedHashSet<GrantedAuthority>();
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication != null && !isEmpty(authentication.getAuthorities())) {
			authorities.addAll(authentication.getAuthorities());
		}
		return authorities;
	}

	/**
	 * Retorna true si y sólo si el usuario logueado tiene asignado a TODOS los permisos consultados.
	 * 
	 * @param tokens - Array de tokens de seguridad a consultar.
	 * @author fabian.lobo
	 */
	public synchronized static boolean poseeTodos(Token... tokens) {
		List<Autorizacion> permisos = new ArrayList<Autorizacion>();
		for(Token token : tokens) {
			permisos.add(new Autorizacion("ROLE_" + token.toString()));
		}
		return permisosDelUsuario().containsAll(permisos);
	}
	
	/**
	 * Retorna true si y sólo si el usuario logueado tiene asignado a alguno los permisos consultados.
	 * 
	 * @param tokens - Array de tokens de seguridad a consultar.
	 * @author fabian.lobo
	 */
	public synchronized static boolean poseeAlguno(Token... tokens) {
		List<Autorizacion> permisos = new ArrayList<Autorizacion>();
		for(Token token : tokens) {
			permisos.add(new Autorizacion("ROLE_" + token.toString()));
		}
		return containsAny(permisosDelUsuario(), permisos);
	}

	/**
	 * Retorna true si y sólo si el usuario logueado NO tiene asignado el permiso consultado.
	 * 
	 * @param token - Token de seguridad a consultar.
	 * @author fabian.lobo
	 */
	public static boolean noPosee(Token token) {
		Autorizacion permiso = new Autorizacion("ROLE_" + token.toString());
		return !containsInstance(permisosDelUsuario(), permiso);
	}

}
